package com.xiguanlezz.cn;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;

import java.util.Iterator;
import java.util.concurrent.TimeUnit;

/**
 * @Author：习惯了种种
 * @CreateDate：2024/10/28 22:27
 * @Description：gRPC客户端实现
 */
@Slf4j
public class GrpcClient {
    public static void main(String[] args) {
        // 普通调用
//        normalGrpc();

        // 服务端流式调用
//        streamedServerGrpc();

        // 客户端流式调用
//        streamedClientGrpc();

        // 双向流式调用
        streamedClientAndServerGrpc();
    }

    private static void normalGrpc() {
        // 创建通信管道
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 8888)
                .usePlaintext().build();

        try {
            // 获取代理对象
            UserServiceGrpc.UserServiceBlockingStub userService = UserServiceGrpc.newBlockingStub(managedChannel);

            // 请求参数构造
            UserServiceProto.LoginRequest request = UserServiceProto.LoginRequest.newBuilder()
                    .setName("xiguanlezz")
                    .setPassword("123456")
                    .build();

            // RPC调用
            UserServiceProto.LoginResponse loginResponse = userService.login(request);
            log.info("result: {}", loginResponse);

        } finally {
            managedChannel.shutdown();
        }
    }

    private static void streamedServerGrpc() {
        // 创建通信管道
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 8888)
                .usePlaintext().build();

        try {
            // 获取代理对象
            UserServiceGrpc.UserServiceBlockingStub userService = UserServiceGrpc.newBlockingStub(managedChannel);

            // 请求参数构造
            UserServiceProto.LoginRequest request = UserServiceProto.LoginRequest.newBuilder()
                    .setName("xiguanlezz")
                    .setPassword("123456")
                    .build();

            // RPC调用，通过迭代器流式异步获取消息
            Iterator<UserServiceProto.LoginResponse> loginResponseIterator = userService.login2(request);
            while (loginResponseIterator.hasNext()) {
                UserServiceProto.LoginResponse response = loginResponseIterator.next();
                log.info("result: {}", response);
            }

            // 防止当前进程过早退出
            managedChannel.awaitTermination(10, TimeUnit.SECONDS);

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            managedChannel.shutdown();
        }
    }

    private static void streamedClientGrpc() {
        // 创建通信管道
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 8888)
                .usePlaintext().build();

        try {
            // 获取代理对象
            UserServiceGrpc.UserServiceStub userService = UserServiceGrpc.newStub(managedChannel);

            // 服务端响应处理器
            StreamObserver<UserServiceProto.LoginResponse> loginResponseStreamObserver = new StreamObserver<UserServiceProto.LoginResponse>() {
                @Override
                public void onNext(UserServiceProto.LoginResponse loginResponse) {
                    log.info("result: {}", loginResponse);
                }

                @Override
                public void onError(Throwable throwable) {

                }

                @Override
                public void onCompleted() {
                    log.info("服务端都处理完了。。。");
                }
            };

            // 客户端请求添加器
            StreamObserver<UserServiceProto.LoginRequest> loginRequestStreamObserver = userService.login3(loginResponseStreamObserver);
            for (int i = 0; i < 5; i++) {
                log.info("这是发给服务端的请求-{}", i + 1);
                UserServiceProto.LoginRequest loginRequest = UserServiceProto.LoginRequest
                        .newBuilder()
                        .setName("xiguanlezz")
                        .setPassword("123456")
                        .build();
                // 将一个请求发给服务提供方
                loginRequestStreamObserver.onNext(loginRequest);
            }
            // 通知服务提供方请求发送完毕
            loginRequestStreamObserver.onCompleted();

            // 防止当前进程过早退出
            managedChannel.awaitTermination(10, TimeUnit.SECONDS);

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            managedChannel.shutdown();
        }
    }

    private static void streamedClientAndServerGrpc() {
        // 创建通信管道
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 8888)
                .usePlaintext().build();

        try {
            // 获取代理对象
            UserServiceGrpc.UserServiceStub userService = UserServiceGrpc.newStub(managedChannel);

            // 服务端响应处理器
            StreamObserver<UserServiceProto.LoginResponse> loginResponseStreamObserver = new StreamObserver<UserServiceProto.LoginResponse>() {
                @Override
                public void onNext(UserServiceProto.LoginResponse loginResponse) {
                    log.info("result: {}", loginResponse);
                }

                @Override
                public void onError(Throwable throwable) {

                }

                @Override
                public void onCompleted() {
                    log.info("服务端都处理完了。。。");
                }
            };

            // 客户端请求添加器
            StreamObserver<UserServiceProto.LoginRequest> loginRequestStreamObserver = userService.login4(loginResponseStreamObserver);
            for (int i = 0; i < 5; i++) {
                log.info("这是发给服务端的请求-{}", i + 1);
                UserServiceProto.LoginRequest loginRequest = UserServiceProto.LoginRequest
                        .newBuilder()
                        .setName("xiguanlezz")
                        .setPassword("123456")
                        .build();
                // 将一个请求发给服务提供方
                loginRequestStreamObserver.onNext(loginRequest);
            }
            // 通知服务提供方请求发送完毕
            loginRequestStreamObserver.onCompleted();

            // 防止当前进程过早退出
            managedChannel.awaitTermination(10, TimeUnit.SECONDS);

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            managedChannel.shutdown();
        }
    }
}
